package com.example.voucher.extension;

import java.util.function.Consumer;
import java.util.function.Function;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.example.voucher.config.TenantMirrorConfig;

@Component
public class ExtensionExecutor {

    @Autowired
    private ExtensionRegister extensionRegister;
    @Autowired
    private ScenarioCapable scenarioCapable;
    @Autowired
    private TenantMirrorConfig mirrorConfig;

    public <T> void executeVoid(Class<T> targetClz, String scenarioCode, Consumer<T> consumer) {
        T component = extensionRegister.locateComponent(targetClz, scenarioCode);
        if (null != component) {
            consumer.accept(component);
        }
    }

    public <R, T> R execute(Class<T> targetClz, String scenarioCode, Function<T, R> func) {
        T component = extensionRegister.locateComponent(targetClz, scenarioCode);
        if (null != component) {
            return func.apply(component);
        }
        return null;
    }

    public <T> void executeVoidByTenantCode(Class<T> targetClz, String tenantCode, Consumer<T> consumer) {
        String scenarioCode = scenarioCapable.getScenarioCode(tenantCode, targetClz);
        if (StringUtils.isBlank(scenarioCode) || ScenarioCapable.SCENARIO_CODE_DEFAULT.equals(scenarioCode)) {
            String mirrorTenantCode = mirrorConfig.getMirror(tenantCode);
            if (StringUtils.isNotBlank(mirrorTenantCode)) {
                String mirrorScenarioCode = scenarioCapable.getScenarioCode(mirrorTenantCode, targetClz);
                if (StringUtils.isNotBlank(mirrorScenarioCode) && !ScenarioCapable.SCENARIO_CODE_DEFAULT.equals(mirrorScenarioCode)) {
                    scenarioCode = mirrorScenarioCode;
                }
            }
        }
        executeVoid(targetClz, scenarioCode, consumer);
    }

    public <R, T> R executeByTenantCode(Class<T> targetClz, String tenantCode, Function<T, R> func) {
        String scenarioCode = scenarioCapable.getScenarioCode(tenantCode, targetClz);
        if (StringUtils.isBlank(scenarioCode) || ScenarioCapable.SCENARIO_CODE_DEFAULT.equals(scenarioCode)) {
            String mirrorTenantCode = mirrorConfig.getMirror(tenantCode);
            if (StringUtils.isNotBlank(mirrorTenantCode)) {
                String mirrorScenarioCode = scenarioCapable.getScenarioCode(mirrorTenantCode, targetClz);
                if (StringUtils.isNotBlank(mirrorScenarioCode) && !ScenarioCapable.SCENARIO_CODE_DEFAULT.equals(mirrorScenarioCode)) {
                    scenarioCode = mirrorScenarioCode;
                }
            }
        }
        return execute(targetClz, scenarioCode, func);
    }

}
